import Foundation
import UIKit
import AsyncDisplayKit
import Display
import SwiftSignalKit
import TelegramCore
import TelegramPresentationData
import ListSectionHeaderNode
import AppBundle
import ItemListUI
import Markdown
import AccountContext
import MergedAvatarsNode
import TextNodeWithEntities
import TextFormat
import AvatarNode

class ChatListNoticeItem: ListViewItem {
    enum Action {
        case activate
        case hide
        case buttonChoice(isPositive: Bool)
    }
    
    let context: AccountContext
    let theme: PresentationTheme
    let strings: PresentationStrings
    let notice: ChatListNotice
    let action: (Action) -> Void
    
    let selectable: Bool = true
    
    init(context: AccountContext, theme: PresentationTheme, strings: PresentationStrings, notice: ChatListNotice, action: @escaping (Action) -> Void) {
        self.context = context
        self.theme = theme
        self.strings = strings
        self.notice = notice
        self.action = action
    }
    
    func selected(listView: ListView) {
        listView.clearHighlightAnimated(true)
        
        self.action(.activate)
    }
    
    func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal<Void, NoError>?, (ListViewItemApply) -> Void)) -> Void) {
        async {
            let node = ChatListNoticeItemNode()
            
            let (nodeLayout, apply) = node.asyncLayout()(self, params, false)
            
            node.insets = nodeLayout.insets
            node.contentSize = nodeLayout.contentSize
            
            Queue.mainQueue().async {
                completion(node, {
                    return (nil, { _ in
                        apply()
                    })
                })
            }
        }
    }
    
    func updateNode(async: @escaping (@escaping () -> Void) -> Void, node: @escaping () -> ListViewItemNode, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, animation: ListViewItemUpdateAnimation, completion: @escaping (ListViewItemNodeLayout, @escaping (ListViewItemApply) -> Void) -> Void) {
        Queue.mainQueue().async {
            assert(node() is ChatListNoticeItemNode)
            if let nodeValue = node() as? ChatListNoticeItemNode {
                
                let layout = nodeValue.asyncLayout()
                async {
                    let (nodeLayout, apply) = layout(self, params, nextItem == nil)
                    Queue.mainQueue().async {
                        completion(nodeLayout, { _ in
                            apply()
                        })
                    }
                }
            }
        }
    }
}

private let separatorHeight = 1.0 / UIScreen.main.scale

private let titleFont = Font.semibold(15.0)
private let titleBoldFont = Font.bold(15.0)
private let titleItalicFont = Font.semiboldItalic(15.0)
private let titleBoldItalicFont = Font.semiboldItalic(15.0)

private let textFont = Font.regular(15.0)
private let textBoldFont = Font.semibold(15.0)
private let textItalicFont = Font.italic(15.0)
private let textBoldItalicFont = Font.semiboldItalic(15.0)

private let smallTextFont = Font.regular(14.0)

final class ChatListNoticeItemNode: ItemListRevealOptionsItemNode {
    private let contentContainer: ASDisplayNode
    private let titleNode: TextNodeWithEntities
    private let textNode: TextNodeWithEntities
    private let arrowNode: ASImageNode
    private let separatorNode: ASDisplayNode
    
    private var avatarNode: AvatarNode?
    private var avatarsNode: MergedAvatarsNode?
    
    private var closeButton: HighlightableButtonNode?
    
    private var okButtonText: TextNode?
    private var cancelButtonText: TextNode?
    private var okButton: HighlightableButtonNode?
    private var cancelButton: HighlightableButtonNode?
    
    private var item: ChatListNoticeItem?
    
    override var apparentHeight: CGFloat {
        didSet {
            self.contentContainer.frame = CGRect(origin: CGPoint(), size: CGSize(width: self.bounds.width, height: self.apparentHeight))
            self.separatorNode.frame = CGRect(origin: CGPoint(x: 0.0, y: self.contentContainer.bounds.height - UIScreenPixel), size: CGSize(width: self.contentContainer.bounds.width, height: UIScreenPixel))
        }
    }
    
    required init() {
        self.contentContainer = ASDisplayNode()
        
        self.titleNode = TextNodeWithEntities()
        self.textNode = TextNodeWithEntities()
        self.arrowNode = ASImageNode()
        self.separatorNode = ASDisplayNode()
        
        super.init(layerBacked: false, dynamicBounce: false, rotated: false, seeThrough: false)
        
        self.contentContainer.clipsToBounds = true
        self.clipsToBounds = true
        
        self.contentContainer.addSubnode(self.titleNode.textNode)
        self.contentContainer.addSubnode(self.textNode.textNode)
        self.contentContainer.addSubnode(self.arrowNode)
        
        self.addSubnode(self.contentContainer)
        self.addSubnode(self.separatorNode)
        
        self.zPosition = 1.0
    }
    
    @objc private func closePressed() {
        guard let item = self.item else {
            return
        }
        item.action(.hide)
    }
    
    override func layoutForParams(_ params: ListViewItemLayoutParams, item: ListViewItem, previousItem: ListViewItem?, nextItem: ListViewItem?) {
        let layout = self.asyncLayout()
        let (_, apply) = layout(item as! ChatListNoticeItem, params, nextItem == nil)
        apply()
    }
    
    func asyncLayout() -> (_ item: ChatListNoticeItem, _ params: ListViewItemLayoutParams, _ isLast: Bool) -> (ListViewItemNodeLayout, () -> Void) {
        let previousItem = self.item
        
        let makeTitleLayout = TextNodeWithEntities.asyncLayout(self.titleNode)
        let makeTextLayout = TextNodeWithEntities.asyncLayout(self.textNode)
        
        let makeOkButtonTextLayout = TextNode.asyncLayout(self.okButtonText)
        let makeCancelButtonTextLayout = TextNode.asyncLayout(self.cancelButtonText)
        
        return { item, params, last in
            let baseWidth = params.width - params.leftInset - params.rightInset
            let _ = baseWidth
            
            let sideInset: CGFloat = params.leftInset + 16.0
            let rightInset: CGFloat = sideInset + 24.0
            var titleRightInset = rightInset - 4.0
            let verticalInset: CGFloat = 9.0
            var spacing: CGFloat = 0.0
            
            let themeUpdated = item.theme !== previousItem?.theme
            
            let titleString: NSAttributedString
            let textString: NSAttributedString
            var avatarPeer: EnginePeer?
            var avatarPeers: [EnginePeer] = []
            
            var okButtonLayout: (TextNodeLayout, () -> TextNode)?
            var cancelButtonLayout: (TextNodeLayout, () -> TextNode)?
            var alignment: NSTextAlignment = .left
            
            switch item.notice {
            case let .clearStorage(sizeFraction):
                let sizeString = dataSizeString(Int64(sizeFraction), formatting: DataSizeStringFormatting(strings: item.strings, decimalSeparator: "."))
                let rawTitleString = item.strings.ChatList_StorageHintTitle(sizeString)
                let titleStringValue = NSMutableAttributedString(attributedString: NSAttributedString(string: rawTitleString.string, font: titleFont, textColor: item.theme.rootController.navigationBar.primaryTextColor))
                if let range = rawTitleString.ranges.first {
                    titleStringValue.addAttribute(.foregroundColor, value: item.theme.rootController.navigationBar.accentTextColor, range: range.range)
                }
                titleString = titleStringValue
                
                textString = NSAttributedString(string: item.strings.ChatList_StorageHintText, font: textFont, textColor: item.theme.rootController.navigationBar.secondaryTextColor)
            case .setupPassword:
                titleString = NSAttributedString(string: item.strings.Settings_SuggestSetupPasswordTitle, font: titleFont, textColor: item.theme.rootController.navigationBar.primaryTextColor)
                textString = NSAttributedString(string: item.strings.Settings_SuggestSetupPasswordText, font: textFont, textColor: item.theme.rootController.navigationBar.secondaryTextColor)
            case let .premiumUpgrade(discount):
                let discountString = "\(discount)%"
                let rawTitleString = item.strings.ChatList_PremiumAnnualUpgradeTitle(discountString)
                let titleStringValue = NSMutableAttributedString(attributedString: NSAttributedString(string: rawTitleString.string, font: titleFont, textColor: item.theme.rootController.navigationBar.primaryTextColor))
                if let range = rawTitleString.ranges.first {
                    titleStringValue.addAttribute(.foregroundColor, value: item.theme.rootController.navigationBar.accentTextColor, range: range.range)
                }
                titleString = titleStringValue
                
                textString = NSAttributedString(string: item.strings.ChatList_PremiumAnnualUpgradeText, font: textFont, textColor: item.theme.rootController.navigationBar.secondaryTextColor)
            case let .premiumAnnualDiscount(discount):
                let discountString = "\(discount)%"
                let rawTitleString = item.strings.ChatList_PremiumAnnualDiscountTitle(discountString)
                let titleStringValue = NSMutableAttributedString(attributedString: NSAttributedString(string: rawTitleString.string, font: titleFont, textColor: item.theme.rootController.navigationBar.primaryTextColor))
                if let range = rawTitleString.ranges.first {
                    titleStringValue.addAttribute(.foregroundColor, value: item.theme.rootController.navigationBar.accentTextColor, range: range.range)
                }
                titleString = titleStringValue
                
                textString = NSAttributedString(string: item.strings.ChatList_PremiumAnnualDiscountText, font: textFont, textColor: item.theme.rootController.navigationBar.secondaryTextColor)
                titleRightInset = sideInset
            case let .premiumRestore(discount):
                let discountString = "\(discount)%"
                let rawTitleString = item.strings.ChatList_PremiumRestoreDiscountTitle(discountString)
                let titleStringValue = NSMutableAttributedString(attributedString: NSAttributedString(string: rawTitleString.string, font: titleFont, textColor: item.theme.rootController.navigationBar.primaryTextColor))
                if let range = rawTitleString.ranges.first {
                    titleStringValue.addAttribute(.foregroundColor, value: item.theme.rootController.navigationBar.accentTextColor, range: range.range)
                }
                titleString = titleStringValue
                
                textString = NSAttributedString(string: item.strings.ChatList_PremiumRestoreDiscountText, font: textFont, textColor: item.theme.rootController.navigationBar.secondaryTextColor)
            case .xmasPremiumGift:
                titleString = parseMarkdownIntoAttributedString(item.strings.ChatList_PremiumXmasGiftTitle, attributes: MarkdownAttributes(body: MarkdownAttributeSet(font: titleFont, textColor: item.theme.rootController.navigationBar.primaryTextColor), bold: MarkdownAttributeSet(font: titleFont, textColor: item.theme.rootController.navigationBar.accentTextColor), link: MarkdownAttributeSet(font: titleFont, textColor: item.theme.rootController.navigationBar.primaryTextColor), linkAttribute: { _ in return nil }))
                textString = NSAttributedString(string: item.strings.ChatList_PremiumXmasGiftText, font: textFont, textColor: item.theme.rootController.navigationBar.secondaryTextColor)
            case .premiumGrace:
                titleString = parseMarkdownIntoAttributedString(item.strings.ChatList_PremiumGraceTitle, attributes: MarkdownAttributes(body: MarkdownAttributeSet(font: titleFont, textColor: item.theme.rootController.navigationBar.primaryTextColor), bold: MarkdownAttributeSet(font: titleFont, textColor: item.theme.rootController.navigationBar.accentTextColor), link: MarkdownAttributeSet(font: titleFont, textColor: item.theme.rootController.navigationBar.primaryTextColor), linkAttribute: { _ in return nil }))
                textString = NSAttributedString(string: item.strings.ChatList_PremiumGraceText, font: textFont, textColor: item.theme.rootController.navigationBar.secondaryTextColor)
            case .setupBirthday:
                titleString = NSAttributedString(string: item.strings.ChatList_AddBirthdayTitle, font: titleFont, textColor: item.theme.rootController.navigationBar.primaryTextColor)
                textString = NSAttributedString(string: item.strings.ChatList_AddBirthdayText, font: textFont, textColor: item.theme.rootController.navigationBar.secondaryTextColor)
            case let .birthdayPremiumGift(peers, _):
                let title: String
                let text: String
                if peers.count == 1, let peer = peers.first {
                    var peerName = peer.compactDisplayTitle
                    if peerName.count > 20 {
                        peerName = peerName.prefix(20).trimmingCharacters(in: .whitespacesAndNewlines) + "\u{2026}"
                    }
                    title = item.strings.ChatList_BirthdaySingleTitle(peerName).string
                    text = item.strings.ChatList_BirthdaySingleText
                } else {
                    title = item.strings.ChatList_BirthdayMultipleTitle(Int32(peers.count))
                    text = item.strings.ChatList_BirthdayMultipleText
                }
                titleString = parseMarkdownIntoAttributedString(title, attributes: MarkdownAttributes(body: MarkdownAttributeSet(font: titleFont, textColor: item.theme.rootController.navigationBar.primaryTextColor), bold: MarkdownAttributeSet(font: titleFont, textColor: item.theme.rootController.navigationBar.accentTextColor), link: MarkdownAttributeSet(font: titleFont, textColor: item.theme.rootController.navigationBar.primaryTextColor), linkAttribute: { _ in return nil }))
                textString = NSAttributedString(string: text, font: textFont, textColor: item.theme.rootController.navigationBar.secondaryTextColor)
                avatarPeers = Array(peers.prefix(3))
            case let .reviewLogin(newSessionReview, totalCount):
                spacing = 2.0
                alignment = .center
                
                var rawTitleString = item.strings.ChatList_SessionReview_PanelTitle
                if totalCount > 1 {
                    rawTitleString = "1/\(totalCount) \(rawTitleString)"
                }
                let titleStringValue = NSMutableAttributedString(attributedString: NSAttributedString(string: rawTitleString, font: titleFont, textColor: item.theme.rootController.navigationBar.primaryTextColor))
                titleString = titleStringValue
                
                textString = NSAttributedString(string: item.strings.ChatList_SessionReview_PanelText(newSessionReview.device, newSessionReview.location).string, font: textFont, textColor: item.theme.rootController.navigationBar.secondaryTextColor)
                
                okButtonLayout = makeOkButtonTextLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.strings.ChatList_SessionReview_PanelConfirm, font: titleFont, textColor: item.theme.list.itemAccentColor), maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - sideInset - rightInset, height: 100.0)))
                cancelButtonLayout = makeCancelButtonTextLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.strings.ChatList_SessionReview_PanelReject, font: titleFont, textColor: item.theme.list.itemDestructiveColor), maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - sideInset - rightInset, height: 100.0)))
            case let .starsSubscriptionLowBalance(amount, peers):
                let title: String
                let text: String
                let starsValue = item.strings.ChatList_SubscriptionsLowBalance_Stars(Int32(clamping: amount.value))
                if let peer = peers.first, peers.count == 1 {
                    title = item.strings.ChatList_SubscriptionsLowBalance_Single_Title(starsValue, peer.compactDisplayTitle).string
                    text = item.strings.ChatList_SubscriptionsLowBalance_Single_Text
                } else {
                    title = item.strings.ChatList_SubscriptionsLowBalance_Multiple_Title(starsValue).string
                    text = item.strings.ChatList_SubscriptionsLowBalance_Multiple_Text
                }
                let attributedTitle = NSMutableAttributedString(string: "⭐️\(title)", font: titleFont, textColor: item.theme.rootController.navigationBar.primaryTextColor)
                if let range = attributedTitle.string.range(of: "⭐️") {
                    attributedTitle.addAttribute(ChatTextInputAttributes.customEmoji, value: ChatTextInputTextCustomEmojiAttribute(interactivelySelectedFromPackId: nil, fileId: 0, file: nil, custom: .stars(tinted: false)), range: NSRange(range, in: attributedTitle.string))
                    attributedTitle.addAttribute(.baselineOffset, value: 2.0, range: NSRange(range, in: attributedTitle.string))
                }
                titleString = attributedTitle
                textString = NSAttributedString(string: text, font: smallTextFont, textColor: item.theme.rootController.navigationBar.secondaryTextColor)
            case let .setupPhoto(accountPeer):
                titleString = NSAttributedString(string: item.strings.ChatList_AddPhoto_Title, font: titleFont, textColor: item.theme.rootController.navigationBar.primaryTextColor)
                textString = NSAttributedString(string: item.strings.ChatList_AddPhoto_Text, font: smallTextFont, textColor: item.theme.rootController.navigationBar.secondaryTextColor)
                avatarPeer = accountPeer
            case .accountFreeze:
                titleString = NSAttributedString(string: item.strings.ChatList_FrozenAccount_Title, font: titleFont, textColor: item.theme.list.itemDestructiveColor)
                textString = NSAttributedString(string: item.strings.ChatList_FrozenAccount_Text, font: smallTextFont, textColor: item.theme.rootController.navigationBar.secondaryTextColor)
            case let .link(_, _, title, subtitle):
                titleString = stringWithAppliedEntities(title.string, entities: title.entities, baseColor: item.theme.list.itemPrimaryTextColor, linkColor: item.theme.list.itemAccentColor, baseFont: titleFont, linkFont: titleFont, boldFont: titleBoldFont, italicFont: titleItalicFont, boldItalicFont: titleBoldItalicFont, fixedFont: titleFont, blockQuoteFont: titleFont, message: nil)
                textString = stringWithAppliedEntities(subtitle.string, entities: subtitle.entities, baseColor: item.theme.list.itemPrimaryTextColor, linkColor: item.theme.list.itemAccentColor, baseFont: textFont, linkFont: textFont, boldFont: textBoldFont, italicFont: textItalicFont, boldItalicFont: textBoldItalicFont, fixedFont: textFont, blockQuoteFont: textFont, message: nil)
            }
            
            var leftInset: CGFloat = sideInset
            if !avatarPeers.isEmpty {
                let avatarsWidth = 30.0 + CGFloat(avatarPeers.count - 1) * 16.0
                leftInset += avatarsWidth + 4.0
            } else if let _ = avatarPeer {
                let avatarsWidth: CGFloat = 40.0
                leftInset += avatarsWidth + 6.0
            }
            
            let titleLayout = makeTitleLayout(TextNodeLayoutArguments(attributedString: titleString, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - leftInset - titleRightInset, height: 100.0), alignment: alignment, lineSpacing: 0.18))
            
            let textLayout = makeTextLayout(TextNodeLayoutArguments(attributedString: textString, maximumNumberOfLines: 10, truncationType: .end, constrainedSize: CGSize(width: params.width - leftInset - rightInset, height: 100.0), alignment: alignment, lineSpacing: 0.18))
            
            var contentSize = CGSize(width: params.width, height: verticalInset * 2.0 + titleLayout.0.size.height + textLayout.0.size.height)
            if let okButtonLayout {
                contentSize.height += okButtonLayout.0.size.height + 20.0
            }
            
            let layout = ListViewItemNodeLayout(contentSize: contentSize, insets: UIEdgeInsets())
            
            return (layout, { [weak self] in
                if let strongSelf = self {
                    strongSelf.item = item
                    
                    if themeUpdated {
                        strongSelf.contentContainer.backgroundColor = item.theme.chatList.pinnedItemBackgroundColor
                        strongSelf.separatorNode.backgroundColor = item.theme.chatList.itemSeparatorColor
                        strongSelf.arrowNode.image = PresentationResourcesItemList.disclosureArrowImage(item.theme)
                    }
                    
                    let _ = titleLayout.1(TextNodeWithEntities.Arguments(context: item.context, cache: item.context.animationCache, renderer: item.context.animationRenderer, placeholderColor: .white, attemptSynchronous: true))
                    if case .center = alignment {
                        strongSelf.titleNode.textNode.frame = CGRect(origin: CGPoint(x: floor((params.width - titleLayout.0.size.width) * 0.5), y: verticalInset), size: titleLayout.0.size)
                    } else {
                        strongSelf.titleNode.textNode.frame = CGRect(origin: CGPoint(x: leftInset, y: verticalInset), size: titleLayout.0.size)
                    }
                    
                    let _ = textLayout.1(TextNodeWithEntities.Arguments(context: item.context, cache: item.context.animationCache, renderer: item.context.animationRenderer, placeholderColor: .white, attemptSynchronous: true))
                    
                    strongSelf.titleNode.visibilityRect = CGRect(origin: CGPoint(), size: CGSize(width: 1000000.0, height: 1000000.0))
                    strongSelf.textNode.visibilityRect = CGRect(origin: CGPoint(), size: CGSize(width: 1000000.0, height: 1000000.0))
                    
                    if case .center = alignment {
                        strongSelf.textNode.textNode.frame = CGRect(origin: CGPoint(x: floor((params.width - textLayout.0.size.width) * 0.5), y: strongSelf.titleNode.textNode.frame.maxY + spacing), size: textLayout.0.size)
                    } else {
                        strongSelf.textNode.textNode.frame = CGRect(origin: CGPoint(x: leftInset, y: strongSelf.titleNode.textNode.frame.maxY + spacing), size: textLayout.0.size)
                    }
                    
                    if !avatarPeers.isEmpty {
                        let avatarsNode: MergedAvatarsNode
                        if let current = strongSelf.avatarsNode {
                            avatarsNode = current
                        } else {
                            avatarsNode = MergedAvatarsNode()
                            avatarsNode.isUserInteractionEnabled = false
                            strongSelf.addSubnode(avatarsNode)
                            strongSelf.avatarsNode = avatarsNode
                        }
                        let avatarSize = CGSize(width: 30.0, height: 30.0)
                        avatarsNode.update(context: item.context, peers: avatarPeers.map { $0._asPeer() }, synchronousLoad: false, imageSize: avatarSize.width, imageSpacing: 16.0, borderWidth: 2.0 - UIScreenPixel, avatarFontSize: 10.0)
                        let avatarsSize = CGSize(width: avatarSize.width + 16.0 * CGFloat(avatarPeers.count - 1), height: avatarSize.height)
                        avatarsNode.updateLayout(size: avatarsSize)
                        avatarsNode.frame = CGRect(origin: CGPoint(x: sideInset - 6.0, y: floor((layout.size.height - avatarsSize.height) / 2.0)), size: avatarsSize)
                    } else if let avatarsNode = strongSelf.avatarsNode {
                        avatarsNode.removeFromSupernode()
                        strongSelf.avatarsNode = nil
                    }
                    
                    if let avatarPeer {
                        let avatarNode: AvatarNode
                        if let current = strongSelf.avatarNode {
                            avatarNode = current
                        } else {
                            avatarNode = AvatarNode(font: avatarPlaceholderFont(size: 13.0))
                            avatarNode.isUserInteractionEnabled = false
                            strongSelf.addSubnode(avatarNode)
                            strongSelf.avatarNode = avatarNode
                            
                            avatarNode.setPeer(context: item.context, theme: item.theme, peer: avatarPeer, overrideImage: .cameraIcon)
                        }
                        let avatarSize = CGSize(width: 40.0, height: 40.0)
                        avatarNode.frame = CGRect(origin: CGPoint(x: sideInset - 6.0, y: floor((layout.size.height - avatarSize.height) / 2.0)), size: avatarSize)
                    } else if let avatarNode = strongSelf.avatarNode {
                        avatarNode.removeFromSupernode()
                        strongSelf.avatarNode = nil
                    }
                    
                    if let image = strongSelf.arrowNode.image {
                        strongSelf.arrowNode.frame = CGRect(origin: CGPoint(x: layout.size.width - sideInset - image.size.width + 8.0, y: floor((layout.size.height - image.size.height) / 2.0)), size: image.size)
                    }
                    
                    let hasCloseButton: Bool
                    switch item.notice {
                    case .xmasPremiumGift, .setupBirthday, .birthdayPremiumGift, .premiumGrace, .starsSubscriptionLowBalance, .setupPhoto, .link:
                        hasCloseButton = true
                    default:
                        hasCloseButton = false
                    }
                                        
                    if let okButtonLayout, let cancelButtonLayout {
                        strongSelf.arrowNode.isHidden = true
                        strongSelf.closeButton?.isHidden = true
                        
                        let okButton: HighlightableButtonNode
                        if let current = strongSelf.okButton {
                            okButton = current
                        } else {
                            okButton = HighlightableButtonNode()
                            strongSelf.okButton = okButton
                            strongSelf.contentContainer.addSubnode(okButton)
                            okButton.addTarget(strongSelf, action: #selector(strongSelf.okButtonPressed), forControlEvents: .touchUpInside)
                        }
                        
                        let cancelButton: HighlightableButtonNode
                        if let current = strongSelf.cancelButton {
                            cancelButton = current
                        } else {
                            cancelButton = HighlightableButtonNode()
                            strongSelf.cancelButton = cancelButton
                            strongSelf.contentContainer.addSubnode(cancelButton)
                            cancelButton.addTarget(strongSelf, action: #selector(strongSelf.cancelButtonPressed), forControlEvents: .touchUpInside)
                        }
                        
                        let okButtonText = okButtonLayout.1()
                        if okButtonText !== strongSelf.okButtonText {
                            strongSelf.okButtonText?.removeFromSupernode()
                            strongSelf.okButtonText = okButtonText
                            okButton.addSubnode(okButtonText)
                        }
                        
                        let cancelButtonText = cancelButtonLayout.1()
                        if cancelButtonText !== strongSelf.okButtonText {
                            strongSelf.cancelButtonText?.removeFromSupernode()
                            strongSelf.cancelButtonText = cancelButtonText
                            cancelButton.addSubnode(cancelButtonText)
                        }
                        
                        let buttonsWidth: CGFloat = max(min(300.0, params.width), okButtonLayout.0.size.width + cancelButtonLayout.0.size.width + 32.0)
                        let buttonWidth: CGFloat = floor(buttonsWidth * 0.5)
                        let buttonHeight: CGFloat = 32.0
                        
                        let okButtonFrame = CGRect(origin: CGPoint(x: floor((params.width - buttonsWidth) * 0.5), y: strongSelf.textNode.textNode.frame.maxY + 6.0), size: CGSize(width: buttonWidth, height: buttonHeight))
                        let cancelButtonFrame = CGRect(origin: CGPoint(x: okButtonFrame.maxX, y: strongSelf.textNode.textNode.frame.maxY + 6.0), size: CGSize(width: buttonWidth, height: buttonHeight))
                        
                        okButton.frame = okButtonFrame
                        cancelButton.frame = cancelButtonFrame
                        
                        okButtonText.frame = CGRect(origin: CGPoint(x: floor((okButtonFrame.width - okButtonLayout.0.size.width) * 0.5), y: floor((okButtonFrame.height - okButtonLayout.0.size.height) * 0.5)), size: okButtonLayout.0.size)
                        cancelButtonText.frame = CGRect(origin: CGPoint(x: floor((cancelButtonFrame.width - cancelButtonLayout.0.size.width) * 0.5), y: floor((cancelButtonFrame.height - cancelButtonLayout.0.size.height) * 0.5)), size: cancelButtonLayout.0.size)
                    } else {
                        strongSelf.arrowNode.isHidden = hasCloseButton
                        
                        if let okButton = strongSelf.okButton {
                            strongSelf.okButton = nil
                            okButton.removeFromSupernode()
                        }
                        if let cancelButton = strongSelf.cancelButton {
                            strongSelf.cancelButton = nil
                            cancelButton.removeFromSupernode()
                        }
                        if let okButtonText = strongSelf.okButtonText {
                            strongSelf.okButtonText = nil
                            okButtonText.removeFromSupernode()
                        }
                        if let cancelButtonText = strongSelf.cancelButtonText {
                            strongSelf.cancelButtonText = nil
                            cancelButtonText.removeFromSupernode()
                        }
                        
                        if hasCloseButton {
                            let closeButton: HighlightableButtonNode
                            if let current = strongSelf.closeButton {
                                closeButton = current
                            } else {
                                closeButton = HighlightableButtonNode()
                                closeButton.hitTestSlop = UIEdgeInsets(top: -8.0, left: -8.0, bottom: -8.0, right: -8.0)
                                closeButton.addTarget(self, action: #selector(strongSelf.closePressed), forControlEvents: [.touchUpInside])
                                strongSelf.contentContainer.addSubnode(closeButton)
                                strongSelf.closeButton = closeButton
                            }
                            
                            if themeUpdated || closeButton.image(for: .normal) == nil {
                                closeButton.setImage(PresentationResourcesItemList.itemListCloseIconImage(item.theme), for: .normal)
                            }
                            
                            let closeButtonSize = closeButton.measure(CGSize(width: 100.0, height: 100.0))
                            closeButton.frame = CGRect(origin: CGPoint(x: layout.size.width - sideInset - closeButtonSize.width, y: floor((layout.size.height - closeButtonSize.height) / 2.0)), size: closeButtonSize)
                        } else {
                            strongSelf.closeButton?.removeFromSupernode()
                            strongSelf.closeButton = nil
                        }
                    }
                    
                    strongSelf.contentSize = layout.contentSize
                    strongSelf.insets = layout.insets
                    
                    strongSelf.updateLayout(size: layout.contentSize, leftInset: params.leftInset, rightInset: params.rightInset)
                    
                    //strongSelf.contentContainer.frame = CGRect(origin: CGPoint(), size: layout.contentSize)
                    
                    switch item.notice {
                    default:
                        strongSelf.setRevealOptions((left: [], right: []))
                    }
                }
            })
        }
    }
    
    override public func selected() {
        super.selected()
        
        if case .setupPhoto = self.item?.notice {
            self.avatarNode?.playCameraAnimation()
        }
    }
    
    @objc private func okButtonPressed() {
        self.item?.action(.buttonChoice(isPositive: true))
    }
    
    @objc private func cancelButtonPressed() {
        self.item?.action(.buttonChoice(isPositive: false))
    }
    
    override public func animateInsertion(_ currentTimestamp: Double, duration: Double, options: ListViewItemAnimationOptions) {
        super.animateInsertion(currentTimestamp, duration: duration, options: options)
        
        //self.transitionOffset = self.bounds.size.height
        //self.addTransitionOffsetAnimation(0.0, duration: duration, beginAt: currentTimestamp)
    }
    
    override public func updateRevealOffset(offset: CGFloat, transition: ContainedViewLayoutTransition) {
        super.updateRevealOffset(offset: offset, transition: transition)
        
        transition.updateSublayerTransformOffset(layer: self.contentContainer.layer, offset: CGPoint(x: offset, y: 0.0))
    }
    
    override public func revealOptionSelected(_ option: ItemListRevealOption, animated: Bool) {
        if let item = self.item {
            item.action(.hide)
        }
        
        self.setRevealOptionsOpened(false, animated: true)
        self.revealOptionsInteractivelyClosed()
    }
}
